/* Copyright (c) 2009-2010, Sean A.O. Harney <sharney3@gmail.com> */

#include "omf.h"



bool builtin_functions_init(void)
{
    //char **funcnames = { "hd", "tl", NULL };//gives compile warnings.
    char *funcnames[] = { "hd", "tl", NULL };
    BUILTIN_FUNC_P func_ptrs[] = { &builtin_func_hd, &builtin_func_tl, NULL };	//parralel to funcnames

    char *funcname;
    int i;

    for (i = 0, funcname = funcnames[0]; funcname != NULL;
	 funcname = funcnames[++i])
      {
	  debug2_printf
	      ("adding built-in function `%s` to global symbol tbl\n",
	       funcname);

	  if (!symbol_tbl_new_entry_function_builtin
	      (glob.symbol_tbl_global, funcname, func_ptrs[i]))
	      return false;	//give up if any fail
      }

    return true;
}


//expects already evaled list
//returns leaf val (could be a list if first element of list was list)
EXPR_P builtin_func_hd(EXPR_P list)
{
    EXPR_P ret = NULL;
    LLIST_P llist;		//llist of evaled exprs.
    if (list->type != EXPR_LEAF || list->u.leaf.type != LEAF_LIST)
	fatal_error_println
	    ("OMF built-in function hd() expects LIST as argument.");

    llist = list->u.leaf.val.list_val;

    if (llist == NULL)		//empty list. NOTE: SML hd []; throws Empty exception
	fatal_error_println
	    ("OMF built-in function hd() used on empty list [].");

    ret = llist->element;	//first element of list.

//TODO: make new EXPR for it.
    return ret;
}


//expects already evaled list
//returns list
EXPR_P builtin_func_tl(EXPR_P list)
{
    LLIST_P llist;		//llist of evaled exprs.

    if (list->type != EXPR_LEAF || list->u.leaf.type != LEAF_LIST)
	fatal_error_println
	    ("OMF built-in function tl() expects LIST as argument.");

    llist = list->u.leaf.val.list_val;

    if (llist == NULL)		//empty list. NOTE: SML tl []; throws Empty exception
	fatal_error_println
	    ("OMF built-in function tl() used on empty list [].");

    // NOTE for list of size 1,eg tl ["a"] is []. (llist->next will be NULL).
    // TODO: copy llist->next perhaps?

    LLIST_P new_llist = NULL;
    LLIST_P walker;

    for (walker = llist->next; walker != NULL; walker = walker->next)	//skip over first element, hd
	llist_append(walker->element, &new_llist);

    return new_expr_leaf_list(new_llist);
}
